package com.lzyyj.gmis.base.dao.hibernate;

import com.lzyyj.common.BeanUtilsExt;
import com.lzyyj.common.GenericsUtils;
import com.lzyyj.common.Page;
import com.lzyyj.gmis.base.dao.IBaseDao;
import com.lzyyj.gmis.base.dao.PersistenceHelper;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.*;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.criterion.*;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Hibernate Dao 的泛型基类.
 * <p/>
 * 继承于Spring的<code>HibernateDaoSupport</code>,提供分页函数和若干便捷查询方法，并对返回值作了泛型类型转换.
 *
 * @author lzyyj
 * @see HibernateDaoSupport
 * @see HibernateEntityDao
 */
@Transactional
@SuppressWarnings("unchecked")
public class HibernateEntityDao<T, PK extends Serializable> extends HibernateDaoSupport implements IHibernateBaseDao<T, PK> {

    private static final Log log = LogFactory.getLog(HibernateEntityDao.class);

    private static Map<Class<?>, HibernateEntityDao<?, Serializable>> daoMap = new HashMap<Class<?>, HibernateEntityDao<?, Serializable>>();

    protected Class<T> entityClass; // DAO所管理的Entity类型.

    private String aliasName = "this_";

    private boolean aggregateRoot = false;

    private Session session;

    /**
     * 非数据库中的固有实体对象 如 Org:0 - 组织机构根对象
     */
    private Map<PK, T> inherentEntities = new HashMap<PK, T>();

    @Override
    public Map<PK, T> getInherentEntities() {
        return inherentEntities;
    }

    public void setInherentEntities(Map<PK, T> inherentEntities) {
        this.inherentEntities = inherentEntities;
    }

    /**
     * 有效表达式
     */
    private String validExpressions = null;

    public String getValidExpressions() {
        return validExpressions;
    }

    public void setValidExpressions(String validExpressions) {
        this.validExpressions = validExpressions;
        // 设置有效表达式，从中分离出相关属性列表，便于需要时自动添加有效表达式
        List<String> list = new ArrayList<String>();
        if (validExpressions != null) {
            for (String prop : validExpressions.split(" ")) {
                if (prop != null && prop.length() > 0) {
                    if (isPersistentProperty(prop)) {
                        list.add(prop);
                    }
                }
            }
            if (list.size() > 0) {
                validateRefProps = (String[]) list.toArray(new String[0]);
            }
        }
    }

    /**
     * 有效表达相关属性
     */
    private String[] validateRefProps;

    protected Map<String, Class<?>> foreignKeyMap = new HashMap<String, Class<?>>();

    @Override
    public Map<String, Class<?>> getForeignKeyMap() {
        return foreignKeyMap;
    }

    public void setForeignKeyMap(Map<String, Class<?>> foreignKeyMap) {
        this.foreignKeyMap = foreignKeyMap;
    }

    public void setForeignKeys(String foreignKeys) {
        if (foreignKeys != null) {
            String[] foreignKeyList = foreignKeys.split(",");
            for (String foreignKey : foreignKeyList) {
                if (foreignKey.length() > 0) {
                    String foreignName;
                    String foreignObject;
                    String[] foreignKeyStr = foreignKey.split(":");
                    switch (foreignKeyStr.length) {
                        case 1:
                            foreignName = foreignKeyStr[0];
                            foreignObject = foreignKeyStr[0];
                            break;
                        case 2:
                            foreignName = foreignKeyStr[0];
                            foreignObject = foreignKeyStr[1];
                            break;
                        default:
                            foreignName = null;
                            foreignObject = null;
                            break;
                    }
                    if (foreignName != null && foreignName.length() > 0) {

                    } else {
                        foreignObject = null;
                    }
                    if (foreignObject != null) {
                    }
                }
            }
        }
    }

    private void parseEntityClass(Class<T> entityClass) {
        String description;
        if (entityClass == null) {
            this.entityClass = (Class<T>) GenericsUtils.getSuperClassGenricType(getClass(), HibernateEntityDao.class, "T");
            description = "默认构造";
        } else {
            this.entityClass = entityClass;

            if (entityClass != null && entityClass != Object.class) {
                daoMap.put(entityClass, (HibernateEntityDao<?, Serializable>) this);
            }

            description = "带参构造";
        }
        description += aggregateRoot ? "聚合根" : "";
        Class<PK> pkClass = (Class<PK>) GenericsUtils.getSuperClassGenricType(getClass(), HibernateEntityDao.class, "PK");
        log.debug(getClass().getSimpleName() + " " + description + "，" + " 管理实体: " + this.entityClass + " 主键：" + pkClass + " ");
    }

    /**
     * 默认构造函数, 通过继承关系确定管理的实体类
     */
    public HibernateEntityDao() {
        parseEntityClass(null);
    }

    /**
     * 带参构造函数，构造时注入管理的实体类
     *
     * @param clazz
     */
    public HibernateEntityDao(Class<T> clazz) {
        parseEntityClass(clazz);
    }

    /**
     * 带参构造函数，构造时注入管理的实体类
     *
     * @param clazz
     */
    public HibernateEntityDao(Class<T> clazz, boolean aggregateRoot) {
        this.aggregateRoot = aggregateRoot;
        parseEntityClass(clazz);
    }

    /**
     * 获取管理的实体类
     */
    @Override
    public Class<T> getEntityClass() {
        return entityClass;
    }

    /**
     * 获得实体类的属性列表
     *
     * @return
     */
    @Override
    public String[] getProperties(Class<?> entityClass) {
        String[] propertyList;

        ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);

        propertyList = meta.getPropertyNames();

        return propertyList;
    }

    /**
     * 获得实体类的属性列表
     *
     * @return
     */
    @Override
    public String[] getProperties() {
        return getProperties(entityClass);
    }

    /**
     * 获得实体类的属性列表
     *
     * @return
     */
    @Override
    public String getPropertyList() {
        StringBuffer fieldList = new StringBuffer();

        if (entityClass == Object.class) {
            fieldList.append("id");
            fieldList.append(",").append("name");
        } else if (isEntity(entityClass)) {
            ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);

            for (String field : meta.getPropertyNames()) {
                if (fieldList.length() != 0) {
                    fieldList.append(",");
                }
                fieldList.append(field);
            }
        }

        return fieldList.toString();
    }

    /**
     * 获取当前可用 Session (如果没有，创建新的 Session)
     *
     * @return
     */
    public Session getCurrentSession() {
        return getHibernateTemplate().getSessionFactory().getCurrentSession();
    }

    /**
     * 保存对象.
     *
     * @throws Exception
     */
    public T save(T o) throws Exception {
        return save(o, null);
    }

    /**
     * 保存对象,并保证属性列表指示的属性能被持久化，
     *
     * @throws Exception
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws Exception
     */
    public T save(T entity, String propertyList) throws Exception {

        T entityPo = get(entity, propertyList);
        // 可能未能被持久化的属性，在主实体持久化后需要检查一下，保证其能被完整地持久化
        if (entityPo == null) {
            entityPo = getNew();
            PK id = getPK(entity);
            if (id != null) {
                PropertyUtils.setProperty(entityPo, getPKName(), id);
            }
            Map<String, String> relevanceMap = PersistenceHelper.copyProperties(entity, entityPo, propertyList, true, this);
            getHibernateTemplate().save(entityPo);
            updateRelevance(entityPo, relevanceMap);
        } else {
            entityPo = update(entity, propertyList);
        }

        return entityPo;
    }

    private void updateRelevance(T entityPo, Map<String, String> relevanceMap) throws NoSuchFieldException, Exception {
        if (relevanceMap != null && relevanceMap.size() > 0) {
            PK pkId = getPK(entityPo);
            for (Entry<String, String> entry : relevanceMap.entrySet()) {
                String propertyName = entry.getKey();
                String fkPropertyName = entry.getValue();

                Class<?> propertyClass = BeanUtilsExt.getPropertyType(entityClass, propertyName);
                Object propertyValue = BeanUtilsExt.getPropertyValue(entityPo, propertyName);
                Class<?> propertyMemberClass;
                IBaseDao<Object, Serializable> dao;
                if (Collection.class.isAssignableFrom(propertyClass)) {
                    propertyMemberClass = BeanUtilsExt.getMemberType(entityClass, propertyName);
                    dao = (IBaseDao<Object, Serializable>) getBaseDao(propertyMemberClass);
                    Collection<Object> collection = (Collection<Object>) propertyValue;
                    if (BeanUtilsExt.isProperty(propertyMemberClass, fkPropertyName)) {
                        for (Object relevanceObj : collection) {
                            BeanUtilsExt.setPropertyValue(relevanceObj, fkPropertyName, pkId);
                            dao.saveOrUpdate(relevanceObj);
                        }
                    }
                } else {
                    propertyMemberClass = propertyClass;
                }
            }
        }
    }

    /**
     * 删除对象.
     */
    @Transactional
    public void delete(Object o) {
        getHibernateTemplate().delete(o);
    }

    /**
     * 根据ID删除对象.
     */
    public void deleteById(PK id) {
        delete(getById(id));
    }

    @Override
    public void deleteByIds(PK[] ids) {
        for (PK id : ids) {
            this.deleteById(id);
        }
    }

    public T update(T entityPo) throws Exception {
        return update(entityPo, null);
    }

    public T update(T entity, String propertyList) throws Exception {
        T entityPo = get(entity, propertyList);
        Map<String, String> relevanceMap = PersistenceHelper.copyProperties(entity, entityPo, propertyList, true, this);
        getHibernateTemplate().update(entityPo);
        updateRelevance(entityPo, relevanceMap);
        return entityPo;
    }

    public T saveOrUpdate(T o) {
        getHibernateTemplate().saveOrUpdate(o);
        return o;
    }

    /**
     * 对符合条件的对象执行指定的更新命令
     *
     * @param hql    查询语句
     * @param values 参数
     */
    public void executeUpdate(String hql, Object... values) {
        String updateHql = "update " + entityClass.getSimpleName() + (hql.indexOf("set ") >= 0 ? " " : " set ") + hql;
        Query query = getQuery(updateHql, values);
        query.executeUpdate();

    }

    @Override
    public T getNew() {
        T entity = null;
        try {
            entity = this.entityClass.newInstance();
        } catch (Exception e) {
            entity = null;
        }
        return entity;
    }

    /**
     * 根据ID获取对象， 如果对象不存在，返回空.
     */
    @Override
    public T get(T entity) {
        return get(entity, null);
    }

    /**
     * 根据ID获取对象， 如果对象不存在，返回空.
     */
    @Override
    public T get(T entity, String propertyList) {
        Optional.ofNullable(entity);

        T entityPo = null;

        PK id;
        try {
            id = this.getPK(entity);
        } catch (Exception e) {
            id = null;
        }
        try {
            entityPo = this.getById(id, propertyList);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return entityPo;
    }

    /**
     * 根据ID获取对象， 如果对象不存在，返回空.
     */
    @Override
    public T getById(PK id) {
        T entityPo = null;

        try {
            entityPo = getById(id, null);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return entityPo;
    }

    /**
     * 根据ID获取对象， 如果对象不存在，返回空.
     *
     * @throws Exception
     */
    @Override
    public T getById(PK id, String propertyList) throws Exception {
        T entityPo = null;

        if (id != null) {
            if (inherentEntities.containsKey(id)) {
                entityPo = inherentEntities.get(id);
            } else {
                entityPo = (T) this.getHibernateTemplate().get(entityClass, id);
                if (entityPo != null) {
                    loadProperties(entityPo, entityClass, propertyList, null);
                }
            }
        }

        return entityPo;
    }

    @Override
    public <E> Map<Class<?>, Map<Serializable, Object>> loadProperties(Collection<E> list, Class<E> entityClass, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache) throws Exception {
        return PersistenceHelper.loadProperties((Collection<Object>) list, (Class<?>) entityClass, propertyList, (Map<Class<?>, Map<Serializable, Object>>) propertyValueCache, (IBaseDao<Object, Serializable>) this);
    }

    @Override
    public Map<Class<?>, Map<Serializable, Object>> loadProperties(Object entityPo, Class<?> entityClass, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache) throws Exception {
        return PersistenceHelper.loadProperties((Object) entityPo, (Class<?>) entityClass, propertyList, (Map<Class<?>, Map<Serializable, Object>>) propertyValueCache, (IBaseDao<Object, Serializable>) this);
    }

    /**
     * 根据ID加载对象. 如果对象不存在，抛出异常.
     *
     * @throws Exception
     */
    @Override
    public T load(PK id) throws Exception {
        Optional.ofNullable(id);
        return (T) this.getHibernateTemplate().load(entityClass, id);
    }

    @Override
    public long getAllCount() {
        long count = 0;

        String hql = "select count(*) from " + entityClass.getSimpleName() + " as " + aliasName + " ";
        if (haveValidExpressions()) {
            hql += aliasName + "." + validExpressions;
        }
        List<Object> result = (List<Object>) getHibernateTemplate().find(hql);
        Long c = (Long) (result.get(0));
        if (c != null)
            count = c.longValue();
        return count;
    }

    public boolean haveValidExpressions() {
        return validExpressions != null && validExpressions.length() > 0;
    }

    public long getCount(Map<String, Object> condition) {
        String jpql = "select count(*) from " + entityClass.getSimpleName() + " as " + aliasName + "";
        String jpqlCondition = (String) condition.get(IHibernateBaseDao.JPQL_CONDITION);

        if (jpqlCondition != null) {
            jpql += " where " + jpqlCondition;
        }

        List<Object> result = (List<Object>) getHibernateTemplate().find(jpql);

        return (Integer) (result.get(0));
    }

    /**
     * 查询符合条件的记录个数
     *
     * @param criteria 条件
     * @return 数量
     */
    public long getCount(Criteria criteria) {
        Optional.ofNullable(criteria);

        CriteriaImpl impl = (CriteriaImpl) criteria;

        // 先把Projection、OrderBy、ResultTransformer取出来,清空三者后再执行Count操作
        Projection projection = impl.getProjection();
        ResultTransformer transformer = impl.getResultTransformer();
        List<CriteriaImpl.OrderEntry> orderEntries;
        try {
            orderEntries = (List<CriteriaImpl.OrderEntry>) BeanUtilsExt.forceGetProperty(impl, "orderEntries");
            BeanUtilsExt.forceSetProperty(impl, "orderEntries", new ArrayList<Object>());
        } catch (Exception e) {
            throw new InternalError(" Runtime Exception impossibility throw ");
        }

        // 执行查询

        long totalCount = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();

        criteria.setProjection(projection);
        if (projection == null) {
            criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
        }
        if (transformer != null) {
            criteria.setResultTransformer(transformer);
        }
        try {
            BeanUtilsExt.forceSetProperty(impl, "orderEntries", orderEntries);
        } catch (Exception e) {
            throw new InternalError(" Runtime Exception impossibility throw ");
        }
        return totalCount;
    }

    /**
     * 判断对象某些属性的值在数据库中是否唯一.
     *
     * @param propertyList 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
     */
    public boolean isUnique(T entityVo, String propertyList) {
        StringUtils.isNotEmpty(propertyList);
        Criteria criteria = createCriteria().setProjection(Projections.rowCount());
        String[] nameList = propertyList.split(",");
        try {
            // 循环加入唯一列
            for (String name : nameList) {
                Object value = PropertyUtils.getProperty(entityVo, name);
                if (value == null) {
                    criteria.add(Restrictions.isNull(name));
                } else {
                    criteria.add(Restrictions.eq(name, value));
                }
            }

            // 以下代码为了如果是update的情况,排除entity自身.

            String idName = getPKName();

            // 取得entity的主键值
            Serializable id = getPK(entityVo);

            // 如果id!=null,说明对象已存在,该操作为update,加入排除自身的判断
            if (id != null)
                criteria.add(Restrictions.not(Restrictions.eq(idName, id)));
        } catch (Exception e) {
            ReflectionUtils.handleReflectionException(e);
        }
        return (Integer) criteria.uniqueResult() == 0;
    }

    /**
     * 根据属性名和属性值查询唯一对象.
     *
     * @return 符合条件的唯一对象 or null if not found.
     */
    public T findUniqueBy(String propertyName, Object value) {
        StringUtils.isNotEmpty(propertyName);
        Criteria criteria = this.createCriteria();

        if (value == null) {
            criteria = criteria.add(Restrictions.isNull(propertyName));
        } else {
            Map<String, Object> condition = new HashMap<String, Object>();
            condition.put(propertyName, value);
            addExampleCriteria(criteria, (T) null, condition, propertyName);
        }

        return (T) criteria.uniqueResult();
    }

    /**
     * 根据属性名和属性值查询唯一对象.
     *
     * @return 符合条件的唯一对象 or null if not found.
     */
    @Override
    public T findUniqueBy(String propertyList, Object... values) {
        StringUtils.isNotEmpty(propertyList);
        Criteria criteria = this.createCriteria();
        String[] fields = propertyList.split(",");
        for (int i = 0; i < fields.length; i++) {
            String field = fields[i];
            Object value = values[i];
            if (field.length() > 0) {
                if (value == null) {
                    criteria = criteria.add(Restrictions.isNull(field));
                } else {
                    criteria = criteria.add(Restrictions.eq(field, value));
                }
            }
        }

        return (T) criteria.uniqueResult();
    }

    /**
     * 根据属性名和属性值查询单个对象.
     *
     * @param criteria 条件
     * @return 对象
     */
    public T findUniqueBy(Criteria criteria) {
        return (T) criteria.uniqueResult();
    }

    /**
     * 获取全部对象.
     */
    @Override
    public List<T> findAll() {
        List<T> list = (List<T>) getHibernateTemplate().loadAll(entityClass);
        return list;
    }

    @Override
    public List<T> findAll(String fieldList, String orderFields, long... firstAndMaxResults) {
        return findAll(orderFields, firstAndMaxResults);
    }

    /**
     * 获取全部对象,带排序字段与升降序参数.
     */
    @Override
    public List<T> findAll(String orderBy, final long... firstAndMaxResults) {
        List<T> list;

        String hqlStr = "select " + aliasName + " from " + entityClass.getSimpleName() + " as " + aliasName + "";

        if (haveValidExpressions()) {
            hqlStr += " where " + aliasName + "." + validExpressions;
        }

        if (orderBy != null && orderBy.trim().length() > 0) {
            hqlStr = hqlStr + " order by " + orderBy;
        }

        final String hql = hqlStr;

        // 调用模板的execute方法，参数是实现了HibernateCallback接口的匿名类，
        list = (List<T>) super.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
            // 重写其doInHibernate方法返回一个object对象，
            public List<T> doInHibernate(Session session) throws HibernateException {
                // 创建query对象
                Query query = session.createQuery(hql);
                // 返回其执行了分布方法的list
                if (firstAndMaxResults.length > 0) {
                    query.setFirstResult((int) firstAndMaxResults[0]);
                }
                if (firstAndMaxResults.length > 1) {
                    query.setMaxResults((int) firstAndMaxResults[1]);
                }
                return query.list();

            }

        });

        return list;
    }

    /**
     * 以参照实例为模板进行查找
     *
     * @param example
     * @return
     * @throws Exception
     */
    public List<T> findByExample(T example, long... firstAndMaxResults) throws Exception {
        return findByExample(example, null, null, null, firstAndMaxResults);
    }

    /**
     * 返回与给定示例的指定的属性相符的对象列表
     *
     * @param example
     * @param examplePropertyList 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
     * @param orderBy
     * @param firstAndMaxResults
     * @throws Exception
     */
    public List<T> findByExample(T example, String examplePropertyList, String orderBy, long... firstAndMaxResults) throws Exception {
        return findByExample(example, examplePropertyList, orderBy, null, firstAndMaxResults);
    }

    /**
     * 返回与给定示例的指定的属性相符的对象列表
     *
     * @param example
     * @param examplePropertyList
     * @param orderBy
     * @param loadPropertyList
     * @param firstAndMaxResults
     * @throws Exception
     */
    public List<T> findByExample(T example, String examplePropertyList, String orderBy, String loadPropertyList, long... firstAndMaxResults) throws Exception {
        List<T> list;
        Criteria criteria = createCriteria();

        addExampleCriteria(criteria, example, null, examplePropertyList);

        this.addOrder(criteria, orderBy);

        addFirstAndMaxResults(criteria, firstAndMaxResults);

        list = (List<T>) criteria.list();

        loadProperties(list, entityClass, loadPropertyList, null);

        return list;
    }

    public List<T> findBy(String condition, long startIndex, long maxCount, String orderBy) {
        String hql = "select " + aliasName + " from " + entityClass.getSimpleName() + " as " + aliasName + "";

        if (condition != null && condition.trim().length() > 0) {
            hql = hql + " where " + condition;
        }

        if (orderBy != null && orderBy.trim().length() > 0) {
            hql = hql + " order by " + orderBy;
        }
        List<T> result = (List<T>) getHibernateTemplate().find(hql);

        return result;
    }

    /**
     * 根据hql查询,直接使用HibernateTemplate的find函数.
     *
     * @param values 可变参数,见{@link #getQuery(String, Object...)}
     */
    @Override
    public List<T> find(String hql, Object... values) {
        StringUtils.isNotEmpty(hql);
        return (List<T>) getHibernateTemplate().find(hql, values);
    }

    /**
     * 根据属性名和属性值查询对象.
     *
     * @return 符合条件的对象列表
     * @throws Exception
     */
    @Override
    public List<T> findByProperty(String propertyName, Object value, String orderBy, String propertyList) throws Exception {
        return findByProperty(propertyName, value, orderBy, propertyList, new long[]{});
    }

    /**
     * 根据属性名和属性值查询指定类型对象.
     *
     * @return 符合条件的对象列表
     * @throws Exception
     */
    @Override
    public <E> List<E> findByProperty(Class<E> entityClass, String propertyName, Object value, String orderBy, long... firstAndMaxResults) throws Exception {
        return findByProperty(entityClass, propertyName, value, orderBy, null, firstAndMaxResults);
    }

    /**
     * 根据属性名和属性值查询指定类型对象.
     *
     * @return 符合条件的对象列表
     * @throws Exception
     */
    @Override
    public <E> List<E> findByProperty(Class<E> clazz, String propertyName, Object value, String orderBy, String propertyList, long... firstAndMaxResults) throws Exception {
        List<E> list = null;

        StringUtils.isNotEmpty(propertyName);

        Map<String, Class<?>> aliasMap = new HashMap<String, Class<?>>();
        Map<String, String> entityAlias = new HashMap<String, String>();

        String alias = aliasName;
        Criteria criteria = createCriteria(clazz, alias);

        addOrder(criteria, orderBy);

        // 是否有属性涉及有效表达式，
        boolean haveRefProp = false;

        Boolean inverse = false;

        // 字符串比较使用like
        Boolean like = true;

        // 字符串比较使用多处like，关键字用空格分隔
        Boolean multiLike = false;

        // 字符串比较仅从开始处比较
        Boolean onlyBegin = true;

        try {
            propertyName = parserCompareMode(propertyName, inverse, like, multiLike, onlyBegin);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 当前主键对象类型
        Class<?> pkEntityClass = clazz;
        // 当前主键对象别名
        String pkAlias = aliasName;
        // 以根实体别名为起始的属性路径
        String propertyPath = pkAlias;
        // 当前实体类默认别名
        aliasMap.put(pkAlias, pkEntityClass);

        // 持久化属性
        String persistentProperty = null;
        Object persistentValue = null;

        // 检查属性中的外键关联
        String[] propertyArray = propertyName.split("\\.");

        // 将最后一级之前的各级属性名，逐级解析，并映射为外键对象
        for (int i = 0; i < propertyArray.length; i++) {
            String currPropertyName = propertyArray[i];
            propertyPath = propertyPath + "." + currPropertyName;
            String currPersistentProperty;

            if (!isPersistentProperty(pkEntityClass, currPropertyName)) {
                log.debug("当前层级属性不是一个持久化属性，必须进行持久化属性映射！");
                Class<?> currPropertyClass;
                currPropertyClass = BeanUtilsExt.getPropertyType(pkEntityClass, currPropertyName);
                if (Collection.class.isAssignableFrom(currPropertyClass)) {
                    currPropertyClass = BeanUtilsExt.getMemberType(pkEntityClass, currPropertyName);
                }

                Entry<String, Class<?>> entry = PersistenceHelper.findForeignKey(currPropertyName, currPropertyClass, foreignKeyMap);
                if (entry != null) {
                    log.debug("找到映射记录！");
                    String[] keyStr = entry.getKey().split(":");
                    if (keyStr.length > 1) {
                        String[] pList = keyStr[1].split("\\.");
                        switch (pList.length) {
                            case 0:
                                break;
                            case 1:
                                // 应是直接的外键属性，如parId、deptUsers
                                currPersistentProperty = pList[0];
                                log.debug("映射为持久化属性：" + currPersistentProperty);
                                try {
                                    persistentValue = BeanUtilsExt.getPropertyValue(value, getPkNameByEntityClass(currPropertyClass));

                                } catch (Exception e1) {
                                    e1.printStackTrace();
                                }
                                persistentProperty = currPersistentProperty;
                                break;
                            default:
                                log.debug("多对一关联");
                                for (int j = 0; j < pList.length - 1; j++) {
                                    currPersistentProperty = pList[j]; // 外键表对象
                                    if (entityAlias.containsKey(propertyPath)) {
                                        // 该级外键已经处理过
                                        alias = entityAlias.get(propertyPath);
                                    } else {
                                        // 获取外键对象类
                                        Class<?> relationObjClass = null;
                                        relationObjClass = BeanUtilsExt.getPropertyType(pkEntityClass, currPersistentProperty);

                                        if (Collection.class.isAssignableFrom(relationObjClass)) {
                                            relationObjClass = BeanUtilsExt.getMemberType(pkEntityClass, currPersistentProperty);
                                            log.debug("是一个一对多外键集合：" + relationObjClass);
                                        } else {
                                            log.debug("是一个多对一外键对象：" + relationObjClass);
                                        }
                                        String relationObjName = relationObjClass.getSimpleName();
                                        relationObjName = relationObjName.substring(0, 1).toLowerCase() + relationObjName.substring(1);
                                        // 未处理过的外键映射，获取一个不会冲突的新别名
                                        alias = getNewAlias(relationObjName, aliasMap);
                                        // 当前类，即关系表中到源类外键关系的主键类主键名
                                        String pkName = getPkNameByEntityClass(pkEntityClass);
                                        // 关系表中关联源类的外键属性名
                                        String fk = null;
                                        // 目标类，即关系表中到目标类外键关系的主键类主键名
                                        String pk2Name = getPkNameByEntityClass(currPropertyClass);
                                        // 关系表中关联目标类的外键属性名
                                        String fk2 = null;
                                        String validExpressions = null;

                                        // 关系表dao
                                        HibernateEntityDao<?, Serializable> dao = getDao(relationObjName);

                                        Map<String, Class<?>> foreignKeyMap = dao.getForeignKeyMap();
                                        if (foreignKeyMap != null) {
                                            for (Entry<String, Class<?>> e : foreignKeyMap.entrySet()) {
                                                if (e.getValue().equals(pkEntityClass)) {
                                                    log.debug("dd");
                                                    fk = e.getKey();
                                                }
                                                if (e.getValue().equals(currPropertyClass)) {
                                                    fk2 = e.getKey();
                                                }
                                            }
                                        }

                                        validExpressions = dao.getValidExpressions();

                                        if (currPropertyClass.equals(dao.getEntityClass())) {
                                            // 应该不可能
                                            log.debug("应该不可能！");
                                        } else {
                                            log.debug("应该是一个关系表：" + dao.getEntityClass());
                                            // 查找到目标类型的外键属性
                                            // 如果下一级就是最后一级，并且属性名是主机名，则持久化属性换成其对应的外键属性名
                                            if (i == (propertyArray.length - 2) && propertyArray[propertyArray.length - 1].equals(pk2Name)) {
                                                entityAlias.put(aliasName + "." + propertyName, alias + "." + fk2);
                                            }
                                        }

                                        log.debug("添加别名：" + propertyPath + " = " + currPersistentProperty + " : " + alias);
                                        criteria.createAlias(pkAlias + "." + currPersistentProperty, alias);

                                        if (validExpressions != null && validExpressions.length() > 0) {
                                            // 目前仅支持一字段名的表达式，并假定是在开始处
                                            // criteria.add(Restrictions.sqlRestriction(alias+"."+validExpressions));
                                        }

                                        aliasMap.put(alias, relationObjClass);
                                        entityAlias.put(propertyPath, alias);
                                    }
                                    pkAlias = alias;
                                }
                                persistentProperty = pList[pList.length - 1];
                                try {
                                    persistentValue = BeanUtilsExt.getPropertyValue(value, getPkNameByEntityClass(currPropertyClass));
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                break;
                        }
                    }
                }
            } else {
                log.debug("当前层级属性是持久化属性，无论类型是否是一个实体类对象，都不用特殊处理！");
                persistentProperty = currPropertyName;
                persistentValue = value;
            }

        }

        if (persistentProperty == null) {
            throw new Exception("未找到有效的持久化属性！");
        }

        if (persistentValue == null) {
            criteria = criteria.add(Restrictions.isNull(pkAlias + "." + persistentProperty));
        } else {
            criteria = criteria.add(Restrictions.eq(pkAlias + "." + persistentProperty, persistentValue));
        }

        if (haveValidExpressions() && !haveRefProp) {
            criteria.add(Restrictions.sqlRestriction(aliasName + "." + validExpressions));
        }

        if (firstAndMaxResults != null && firstAndMaxResults.length > 0) {
            addFirstAndMaxResults(criteria, firstAndMaxResults);
        }

        list = (List<E>) criteria.list();
        Map<Class<?>, Map<Serializable, Object>> propertyValueCache = new HashMap<Class<?>, Map<Serializable, Object>>();
        loadProperties(list, clazz, propertyList, propertyValueCache);
        if (list != null && !propertyName.equals(persistentProperty)) {
            // 外键属性缓存
            for (E entityPo : list) {
                try {
                    BeanUtilsExt.setPropertyValue(entityPo, propertyName, value);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        return list;
    }

    /**
     * 获取集合外键成员类型
     *
     * @param clazz1       持久化类
     * @param propertyName 属性名
     * @return 结果
     */
    private Class<?> getForeignKeyType(Class<?> clazz1, String propertyName) {
        Class<?> foreignKeyType = null;

        ClassMetadata meta = getSessionFactory().getClassMetadata(clazz1);
        if (meta != null) {
            // 指定类型是一个实体类

            // 获取指定属性类型
            org.hibernate.type.Type type1 = meta.getPropertyType(propertyName);

            if (type1 != null && type1.isCollectionType()) {
                // 指定属性类型为集合类型
                foreignKeyType = type1.getReturnedClass();
            }
        }

        return foreignKeyType;
    }

    /**
     * 根据属性名和属性值查询对象.
     *
     * @param propertyName       属性名
     * @param value              值
     * @param orderBy            排序
     * @param firstAndMaxResults 分页
     * @return 结果
     * @throws Exception 可能的异常
     */
    @Override
    public List<T> findByProperty(String propertyName, Object value, String orderBy, long... firstAndMaxResults) throws Exception {
        return (List<T>) findByProperty(entityClass, propertyName, value, orderBy, firstAndMaxResults);
    }

    /**
     * 根据属性名和属性值查询对象.
     *
     * @param propertyName       属性名
     * @param value              值
     * @param orderBy            排序
     * @param propertyList       属性列表
     * @param firstAndMaxResults 分页参数
     * @return 结果
     * @throws Exception 可能的异常
     */
    @Override
    public List<T> findByProperty(String propertyName, Object value, String orderBy, String propertyList, long... firstAndMaxResults) throws Exception {

        List<T> list = (List<T>) findByProperty(entityClass, propertyName, value, orderBy, propertyList, firstAndMaxResults);

        return list;
    }

    /**
     * 根据属性名和属性值查询对象,带排序参数.
     *
     * @param page         分页参数
     * @param propertyName 属性名
     * @param value        值
     * @return 符合条件的对象列表
     */
    public Page<T> findByProperty(Page<T> page, String propertyName, Object value) {
        Criteria criteria = createCriteria();

        String alias = "";
        String propertyString = propertyName;
        while (propertyString.indexOf(".") > 0) {
            // 需要关联外键
            if (alias.length() > 0) {
                alias += ".";
            }
            alias += propertyString.substring(0, propertyString.indexOf("."));
            propertyString = propertyString.substring(propertyString.indexOf(".") + 1);
            criteria.createAlias(alias, alias);
        }

        if (value == null) {
            criteria = criteria.add(Restrictions.isNull(propertyName));
        } else {
            criteria = criteria.add(Restrictions.eq(propertyName, value));
        }
        addOrder(criteria, page.getOrderFields());

        return this.find(page, criteria);
    }

    /**
     * 创建Query对象. 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
     * 留意可以连续设置,如下：
     *
     * <pre>
     * dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
     * </pre>
     * <p>
     * 调用方式如下：
     *
     * <pre>
     *        dao.createQuery(hql)
     *        dao.createQuery(hql,arg0);
     *        dao.createQuery(hql,arg0,arg1);
     *        dao.createQuery(hql,new Object[arg0,arg1,arg2])
     * </pre>
     *
     * @param values 可变参数.
     */
    public Query getQuery(String hql, Object... values) {
        StringUtils.isNotEmpty(hql);
        Query query = (Query) getCurrentSession().createQuery(hql);
        for (int i = 0; i < values.length; i++) {
            query.setParameter(i, values[i]);
        }
        return query;
    }

    /**
     * 创建Criteria对象.
     *
     * @param clazz      可变的Restrictions条件列表,见{@link #getQuery(String, Object...)}
     * @param aliasNames 别名
     * @return 查询
     */
    public Criteria createCriteria(Class<?> clazz, String aliasNames) {
        return getCurrentSession().createCriteria(clazz, aliasNames);
    }

    /**
     * 创建Criteria对象.
     *
     * @return 查询
     */
    public Criteria createCriteria() {
        return createCriteria(entityClass, aliasName);
    }

    /**
     * @param page 分页查询参数
     * @return page对象
     * @author Scott.wanglei
     * @since 2008-7-21
     */
    @Override
    public Page<T> find(Page<T> page) {

        T example = page.getFindByExample();

        String jpql = (String) page.getCondition().get(JPQL);
        Object[] values = (Object[]) page.getCondition().get(VALUES);

        String orderBy = page.getOrderFields();

        String propertyList = (String) page.getCondition().get(PROPERTY_LIST);

        String exampleProperties = (String) page.getCondition().get(EXAMPLE_PROPERTIES);

        Criteria criteria = this.createCriteria();

        if (example == null) {
            if (jpql != null) {
                // jpql 查询 , 先统计数量
                String countQueryString = " select count (*) " + removeSelect(removeOrders(jpql));
                List<T> countlist = (List<T>) getHibernateTemplate().find(countQueryString, values);
                long totalCount = (Integer) countlist.get(0);
                page.setTotalCount(totalCount);

                if (totalCount > 0) {
                    Query query = getQuery(jpql, values);

                    if (page.getStartIndex() > 0) {
                        query.setFirstResult((int) page.getStartIndex());
                    }

                    if (page.getPageSize() > 0) {
                        query.setMaxResults((int) page.getPageSize());
                    }

                    List<T> list = query.list();

                    page.setData(list);
                }
            } else {
                // 无条件
                page.setTotalCount(this.getAllCount());
                List<T> list = this.findAll(orderBy, page.getStartIndex(), page.getPageSize());
                page.setData(list);
            }
        } else {
            // 根据 example 构建查询条件
            criteria = this.addExampleCriteria(criteria, example, page.getCondition(), exampleProperties);

            this.addOrder(criteria, orderBy);

            page = find(page, criteria);
        }

        page.getCondition().put(EXAMPLE_PROPERTIES, exampleProperties);

        if (propertyList == null || propertyList.length() == 0) {
            propertyList = getPropertyList();
            page.getCondition().put(PROPERTY_LIST, propertyList);
        }

        return page;
    }

    /**
     * 分页查询函数，使用已设好查询条件与排序的<code>Criteria</code>.
     *
     * @param page     页号,从1开始, -1或超过总记录数，调整为最后一页.
     * @param criteria 条件
     * @return 含总记录数和当前页数据的Page对象.
     */
    @Override
    public Page<T> find(Page<T> page, Criteria criteria) {
        Optional.ofNullable(criteria);

        if (page.getTotalCount() == -1) {
            page.setTotalCount(getCount(criteria));
        }

        if (page.getTotalCount() >= 0) {

            if (page.getPageNo() < 0 && page.getPageSize() > 0 && page.getTotalPageCount() > 0) {
                // 有分页时及总页数，如果页号为负数，将其调整为倒数页号
                page.setPageNo((page.getTotalPageCount() + page.getPageNo() + 1));
            }

            if (page.getStartIndex() > 0) {
                criteria.setFirstResult((int) page.getStartIndex());
            }

            if (page.getPageSize() > 0) {
                criteria.setMaxResults((int) page.getPageSize());
            }

            List<T> list = criteria.list();

            page.setData(list);
        } else {
            page.setStartIndex(0);
            page.setData(new ArrayList<T>());
        }

        return page;
    }

    /**
     * 获得指定对象在指定查询条件下的位置序号，0算起
     *
     * @param focus 焦点实体对象
     * @param page  查询条件
     * @return 序号
     */
    @Override
    public long getIndex(T focus, Page<T> page) {
        Criteria criteria = createCriteria();
        String orderByString = (String) page.getCondition().get(PROPERTY_LIST);
        if (orderByString == null)
            orderByString = getPKName();
        criteria = this.addExampleCriteria(criteria, page.getFindByExample(), page.getCondition(), orderByString);

        this.addOrder(criteria, orderByString);

        return getIndex(focus, criteria, orderByString);
    }

    /**
     * 查询指定对象在指定查询条件下的位置序号
     *
     * @param focus    焦点实体对象
     * @param criteria 条件
     * @param orderBy  排序列表
     * @return 结果
     * @throws Exception 可能的异常
     */
    @Override
    public long getIndex(T focus, final Criteria criteria, String orderBy) {
        long index = -1;

        T focusPo = (T) this.get(focus);

        if (focusPo != null) {
            String[] orderFields = orderBy.split(",");
            for (String orderField : orderFields) {
                String field = null;
                boolean isAsc = true;
                String[] orderString = orderField.split(" ");
                if (orderString.length > 0) {
                    field = orderString[0];
                }
                if (orderString.length > 1 && "DESC".equalsIgnoreCase(orderString[1])) {
                    isAsc = false;
                }
                if (field != null && field.length() > 0) {
                    Object value = null;
                    try {
                        value = PropertyUtils.getProperty(focusPo, field);
                    } catch (Exception e) {
                        value = null;
                    }
                    if (value != null) {
                        if (isAsc) {
                            criteria.add(Restrictions.le(field, value));
                        } else {
                            criteria.add(Restrictions.ge(field, value));
                        }
                    }
                }
            }
            index = (long) getCount(criteria);
        }

        return index;
    }

    /**
     * 根据示例对象及其他条件构造查询条件
     *
     * @param criteria
     * @param example      示例对象，存放有参考值
     * @param condition    存放条件
     * @param propertyList 要查询的属性名列表
     * @return
     */
    private Criteria addExampleCriteria(Criteria criteria, T example, Map<String, Object> condition, String propertyList) {
        if (criteria == null)
            criteria = createCriteria();

        // 实体外键映射表，key为属性访问路径，value 为相应层级对象映射别名
        Map<String, String> entityAlias = new HashMap<String, String>();
//		entityAlias.put(aliasName, entityClass);

        // 别名-实体映射表, key 为别名，value 为映射的实体类
        Map<String, Class<?>> aliasMap = new HashMap<String, Class<?>>();

        ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);
        Map<String, Object> propertyTypes = new HashMap<String, Object>();
        for (PropertyDescriptor property : PropertyUtils.getPropertyDescriptors(entityClass)) {
            propertyTypes.put(property.getName(), property.getPropertyType());
        }

        String[] propertyArray;
        // 是否有有效表达式相关属性
        boolean haveRefProp = false;

        // 是否有指定的属性列表
        if (propertyList == null || propertyList.trim().length() == 0) {
            // 没有，根据有值的属性构造查询条件
            // 所有属性的列表
            propertyArray = meta.getPropertyNames();
        } else {
            // 有指定的属性列表，根据属性列表构造查询条件
            propertyArray = propertyList.split(",");
        }

        try {
            // 遍历属性列表,按属性加入条件
            for (String propertyName : propertyArray) {
                Object value = null;

                if (example != null) {
                    Boolean inverse = false;

                    // 字符串比较使用like
                    Boolean like = true;

                    // 字符串比较使用多处like，关键字用空格分隔
                    Boolean multiLike = false;

                    // 字符串比较仅从开始处比较
                    Boolean onlyBegin = true;

                    propertyName = parserCompareMode(propertyName, inverse, like, multiLike, onlyBegin);

                    List<Class<?>> valueClasses = new ArrayList<Class<?>>();

                    // 解析出相关持久化属性值，属性名及属性类型
                    value = getPersistentPropertyValue(example, propertyName, entityClass, aliasMap, valueClasses, entityAlias, criteria);
                    String persistentProperty = entityAlias.get(aliasName + "." + propertyName);
                    Class<?> valueClass = valueClasses.get(valueClasses.size() - 1);

                    if (propertyName != null) {
                        if (value == null || value instanceof String && ((String) value).length() == 0) {
                            // 参考值为空或空串
                            if (condition != null && condition.containsKey(propertyName)) {
                                // 条件集合中有附加条件
                                value = condition.get(propertyName);
                                if (value instanceof List) {

                                }
                            } else {
                                // 没有附加条件, 看属性列表是否是明确指定的
                                if (propertyList != null && propertyList.trim().length() > 0) {
                                    // 属性列表非空，即为明确指定要比较的属性，必须作为条件
                                    if (inverse) {
                                        criteria.add(Restrictions.isNotNull(persistentProperty));
                                    } else {
                                        if (valueClass.equals(Integer.class)) {
                                            criteria.add(Restrictions.or(Restrictions.isNull(persistentProperty), Restrictions.eq(persistentProperty, 0)));
                                        } else {
                                            criteria.add(Restrictions.isNull(persistentProperty));
                                        }
                                    }
                                }
                            }
                        } else {
                            // 有值
                            if (isEntity(valueClass)) {
                                // 是持久化对象
                                String fkName = getPkNameByEntityClass(valueClass);
                                Serializable fk = (PK) PropertyUtils.getProperty(value, fkName);
                                if (fk != null) {
                                    value = getBaseDao(valueClass).getById(fk);
                                    if (value != null) {
                                        // 属性列表非空，即为明确指定要比较的属性，必须作为条件
                                        if (inverse) {
                                            criteria.add(Restrictions.not(Restrictions.eq(persistentProperty, value)));
                                        } else {
                                            criteria.add(Restrictions.eq(persistentProperty, value));
                                        }
                                    }
                                }
                                log.debug("fk = " + fk);
                            } else {
                                // 不是持久化对象
                                if (value instanceof String) {
                                    // 字符串值
                                    if (like) {
                                        // like比较
                                        if (onlyBegin) {
                                            // 仅起始位置比较
                                            if (inverse) {
                                                criteria.add(Restrictions.not(Restrictions.like(persistentProperty, value + "%")));
                                            } else {
                                                criteria.add(Restrictions.like(persistentProperty, value + "%"));
                                            }
                                        } else {
                                            String strValue;
                                            if (multiLike) {
                                                // 多关键字比较
                                                strValue = ((String) value).replaceAll(" ", "%");
                                                strValue = strValue.replaceAll("%%", "%");
                                            } else {
                                                strValue = (String) value;
                                            }
                                            if (inverse) {
                                                criteria.add(Restrictions.not(Restrictions.like(persistentProperty, "%" + strValue + "%")));
                                            } else {
                                                criteria.add(Restrictions.like(persistentProperty, "%" + strValue + "%"));
                                            }
                                        }
                                    } else {
                                        // 非like比较
                                        if (inverse) {
                                            criteria.add(Restrictions.not(Restrictions.eq(persistentProperty, value)));
                                        } else {
                                            criteria.add(Restrictions.eq(persistentProperty, value));
                                        }
                                    }
                                } else if (value instanceof Collection) {
                                    // 参考值为集合
                                    Collection<?> collection = (Collection<?>) value;
                                    if (collection.size() == 0) {
                                        // 集合为空
                                        if (condition != null && condition.containsKey(persistentProperty)) {
                                            // 条件集合中有附加条件
                                            value = condition.get(persistentProperty);
                                            if (value instanceof List) {

                                            }
                                        } else {
                                            // 没有附加条件, 看属性列表是否是明确指定的
                                            if (propertyList != null && propertyList.trim().length() > 0) {
                                                // 属性列表非空，即为明确指定要比较的属性，必须作为条件
                                                if (inverse) {
                                                    criteria.add(Restrictions.isNotEmpty(persistentProperty));
                                                } else {
                                                    criteria.add(Restrictions.isEmpty(persistentProperty));
                                                }
                                            }
                                        }
                                    } else {
                                        criteria.add(Restrictions.in(persistentProperty, collection));
                                    }
                                } else {
                                    // 非字符串值、非集合
                                    if (inverse) {
                                        criteria.add(Restrictions.not(Restrictions.eq(persistentProperty, value)));
                                    } else {
                                        criteria.add(Restrictions.eq(persistentProperty, value));
                                    }
                                }
                            }
                        }
                    }
                }

                // 是否有相应属性的其他条件
                if (condition != null && condition.containsKey(propertyName)) {
                    value = condition.get(propertyName);
                    if (value != null) {
                        if ((value.getClass().isArray() || value instanceof List)) {
                            criteria.add(Restrictions.in(propertyName, (List<?>) value));
                        } else {
                            criteria.add(Restrictions.eq(propertyName, value));
                        }
                    } else {
                        criteria.add(Restrictions.isNull(propertyName));
                    }
                }

            }

            if (haveValidExpressions() && !haveRefProp) {
                criteria.add(Restrictions.sqlRestriction(aliasName + "." + validExpressions));
            }
        } catch (Exception e) {
            ReflectionUtils.handleReflectionException(e);
        }

        return criteria;
    }

    /**
     * 从字段名中解析比较模式并将其分离出来
     *
     * @param nameString 名字串
     * @param inverse    取反
     * @param like       模糊查询
     * @param multiLike  前后模糊查询
     * @param onlyBegin  仅开始
     * @return 结果
     * @throws Exception 可能的异常
     */
    public static String parserCompareMode(String nameString, Boolean inverse, Boolean like, Boolean multiLike, Boolean onlyBegin) throws Exception {

        if (nameString.startsWith("!")) {
            inverse = true;
            nameString = nameString.substring(1);
        }
        // 对于字符串字段，强调是相等匹配
        if (nameString.startsWith("=")) {
            like = false;
            nameString = nameString.substring(1);
        }
        // 强调是起始要匹配
        if (nameString.startsWith("%")) {
            like = true;
            nameString = nameString.substring(1);
        }
        // 强调是中间有匹配
        if (nameString.endsWith("%%")) {
            like = true;
            multiLike = true;
            onlyBegin = false;
            nameString = nameString.substring(0, nameString.indexOf("%%"));
        }
        // 强调结尾匹配
        if (nameString.endsWith("%")) {
            like = true;
            multiLike = false;
            nameString = nameString.substring(0, nameString.indexOf("%"));
        }
        return nameString;
    }

    /**
     * 获取持久化的属性值，逐级分析属性描述, 外键关联的添加外键别名,非持久化属性映射成为持久化属性
     *
     * @param clazz
     * @param example
     * @param propertyName
     * @param aliasMap
     * @return
     * @throws Exception
     */
    public Object getPersistentPropertyValue(T example, String propertyName, Class<T> clazz, Map<String, Class<?>> aliasMap, List<Class<?>> valueClasses, Map<String, String> entityAlias, Criteria criteria) throws Exception {
        Object persistentPropertyValue = null;

        // 当前主键对象实体
        Object pkEntity = example;
        // 当前主键对象类型
        Class<?> pkEntityClass = clazz == null ? example.getClass() : clazz;
        // 当前主键对象别名
        String pkAlias = aliasName;
        // 以根实体别名为起始的属性路径
        String propertyPath = pkAlias;
        // 当前实体类默认别名
        aliasMap.put(aliasName, pkEntityClass);

        // 检查属性中的外键关联
        String[] names = propertyName.split("\\.");

        String currPropertyName = null;
        Class<?> fkEntityClass = null;
        Object fkEntity = null;
        String alias = null;
        // 将最后一级之前的各级属性名，逐级解析，并映射为外键对象
        for (int i = 0; i < names.length; i++) {
            if (pkEntity == null) {
                // 上级解析出的实体为空，不正确，无法继续解析
                throw new Exception("指定携带查询参数的对象不存在：" + propertyPath);
            }

            currPropertyName = names[i];
            String persistentProperty;
            propertyPath = propertyPath + "." + currPropertyName;

            // 迭代为下一级关联对象

            fkEntityClass = BeanUtilsExt.getPropertyType(pkEntityClass, currPropertyName);
            fkEntity = PropertyUtils.getProperty(pkEntity, currPropertyName);

            // 如果该属性为集合类型，类型改取其成员类型，值取其第一个成员的值，去不到则为null
            if (Collection.class.isAssignableFrom(fkEntityClass) && fkEntity != null) {
                boolean have = false;
                if (((Collection<?>) fkEntity).size() > 0) {
                    fkEntityClass = BeanUtilsExt.getMemberType(pkEntityClass, currPropertyName);
                    // 如果是一个非空集合类型，才需要关联，并且只取一个条目
                    for (Object item : (Collection<?>) fkEntity) {
                        if (item != null) {
                            fkEntity = item;
                            have = true;
                            break;
                        }
                    }
                }
                if (!have)
                    fkEntity = null;
            }

            if (isEntity(fkEntityClass)) {
                // 关联对象是实体
                log.debug("关联对象是实体");
                if (isPersistentProperty(currPropertyName)) {
                    // 是一个直接关联了的外键对象
                    log.debug("属性是持久化属性");

                    // 当前属性就是持久化属性
                    persistentProperty = currPropertyName;

                    // 还有下一级吗？
                    if (i < names.length - 1) {
                        // 这不是最后一级，必添加别名
                        if (entityAlias.containsKey(propertyPath)) {
                            // 该级外键已经处理过
                            alias = entityAlias.get(propertyPath);
                        } else {
                            // 获取一个不会冲突的新别名
                            alias = getNewAlias(currPropertyName, aliasMap);
                            String associationPath = propertyPath;

                            criteria.createAlias(associationPath, alias);

                            aliasMap.put(alias, fkEntityClass);
                            entityAlias.put(propertyPath, alias);
                        }
                    }
                } else {
                    log.debug("属性是非持久化的外键对象属性");
                    // 查找外键关联记录
                    Entry<String, Class<?>> entry = PersistenceHelper.findForeignKey(currPropertyName, fkEntityClass, foreignKeyMap);
                    if (entry != null) {
                        String[] keyStr = entry.getKey().split(":");
                        if (keyStr.length > 1) {
                            String[] pList = keyStr[1].split("\\.");
                            for (int j = 0; j < pList.length; j++) {
                                String currPersistentProperty = pList[j]; // 外键表对象
                                if (j < pList.length - 1) {
                                    // 中间级
                                    // 需反向关联,如 DeptUser .deptId
                                    if (entityAlias.containsKey(propertyPath)) {
                                        // 该级外键已经处理过
                                        alias = entityAlias.get(propertyPath);
                                    } else {
                                        // 获取外键对象类
                                        Class<?> relationObjClass = BeanUtilsExt.getPropertyType(pkEntityClass, currPersistentProperty);

                                        if (Collection.class.isAssignableFrom(relationObjClass)) {
                                            log.debug("是一个一对多关系表");
                                            relationObjClass = BeanUtilsExt.getMemberType(pkEntityClass, currPersistentProperty);
                                        } else {
                                            log.debug("aa");
                                        }
                                        // 未处理过的外键映射，获取一个不会冲突的新别名
                                        alias = getNewAlias(currPersistentProperty, aliasMap);
                                        // 当前类，即关系表中到源类外键关系的主键类主键名
                                        String pkName = getPkNameByEntityClass(pkEntityClass);
                                        // 关系表中关联源类的外键属性名
                                        String fk = null;
                                        // 目标类，即关系表中到目标类外键关系的主键类主键名
                                        String pk2Name = getPkNameByEntityClass(fkEntityClass);
                                        // 关系表中关联目标类的外键属性名
                                        String fk2 = null;
                                        String validExpressions = null;

                                        // 关系表dao
                                        HibernateEntityDao<?, Serializable> dao = getBaseDao(relationObjClass);

                                        Entry<String, Class<?>> en = PersistenceHelper.findForeignKey(currPersistentProperty, pkEntityClass, dao.getForeignKeyMap());
                                        if (en != null) {
                                            String[] p = en.getKey().split(":");
                                            if (p.length > 1) {
                                                fk = p[1];
                                            }
                                        }
                                        en = PersistenceHelper.findForeignKey(currPersistentProperty, fkEntityClass, dao.getForeignKeyMap());
                                        if (en != null) {
                                            String[] p = en.getKey().split(":");
                                            if (p.length > 1) {
                                                fk2 = p[1];
                                            }
                                        }

                                        validExpressions = dao.getValidExpressions();

                                        if (fkEntityClass.equals(dao.getEntityClass())) {
                                            // 应该不可能
                                            log.debug("应该不可能！");
                                        } else {
                                            log.debug("应该是一个关系表：" + dao.getEntityClass());
                                            // 查找到目标类型的外键属性
                                            // 如果下一级就是最后一级，并且属性名是主机名，则持久化属性换成其对应的外键属性名
                                            if (i == (names.length - 2) && names[names.length - 1].equals(pk2Name)) {
                                                entityAlias.put(aliasName + "." + propertyName, alias + "." + fk2);
                                            }
                                        }

                                        log.debug("添加别名：" + propertyPath + " = " + currPersistentProperty + " : " + alias);
                                        criteria.createAlias(pkAlias + "." + currPersistentProperty, alias);

                                        if (validExpressions != null && validExpressions.length() > 0) {
                                            // 目前仅支持一字段名的表达式，并假定是在开始处
                                            criteria.add(new SQLCriterion("{" + alias + "}" + "." + validExpressions, new Object[0], new Type[0]));
//											criteria.add(Restrictions.sqlRestriction(alias+"."+validExpressions));
                                        }

                                        aliasMap.put(alias, relationObjClass);
                                        entityAlias.put(propertyPath, alias);
                                    }
                                } else {
                                    persistentProperty = currPersistentProperty;
                                    // 主属性末级
                                    // 应是直接的外键属性，如parId、deptUsers
                                    if (i == names.length - 1) {
                                        // 末级属性
                                        // 映射后的类型，应该是主键类型
                                        String fkIdName = getPkNameByEntityClass(fkEntityClass);
                                        fkEntityClass = BeanUtilsExt.getPropertyType(fkEntityClass, fkIdName);
                                        if (pkEntity != null) {
                                            fkEntity = (Serializable) PropertyUtils.getProperty(fkEntity, fkIdName);
                                        }
                                        entityAlias.put(aliasName + "." + propertyName, pkAlias + "." + persistentProperty);
                                    } else {
                                        // 非末级属性
                                        log.debug("注意：应是直接的外键属性，如parId, 中间级！");
                                        if (entityAlias.containsKey(propertyPath)) {
                                            // 该级外键已经处理过
                                            alias = entityAlias.get(propertyPath);
                                        } else {
                                            // 获取外键对象类
                                            Class<?> relationObjClass = BeanUtilsExt.getPropertyType(pkEntityClass, currPersistentProperty);

                                            // 未处理过的外键映射，获取一个不会冲突的新别名
                                            alias = getNewAlias(currPropertyName, aliasMap);
                                            // 当前类，即关系表中到源类外键关系的主键类主键名
                                            String pkName = getPkNameByEntityClass(pkEntityClass);
                                            // 关系表中关联源类的外键属性名
                                            String fk = null;
                                            // 目标类，即关系表中到目标类外键关系的主键类主键名
                                            String pk2Name = getPkNameByEntityClass(fkEntityClass);
                                            // 关系表中关联目标类的外键属性名
                                            String fk2 = null;
                                            String validExpressions = null;

                                            // 关系表dao
                                            HibernateEntityDao<?, Serializable> dao = getBaseDao(relationObjClass);

                                            Map<String, Class<?>> foreignKeyMap = dao.getForeignKeyMap();
                                            if (foreignKeyMap != null) {
                                                for (Entry<String, Class<?>> e : foreignKeyMap.entrySet()) {
                                                    if (e.getValue().equals(pkEntityClass)) {
                                                        log.debug("dd");
                                                        fk = e.getKey();
                                                    }
                                                    if (e.getValue().equals(fkEntityClass)) {
                                                        fk2 = e.getKey();
                                                    }
                                                }
                                            }
                                            validExpressions = dao.getValidExpressions();

                                            if (fkEntityClass.equals(dao.getEntityClass())) {
                                                // 应该不可能
                                                log.debug("应该不可能！");
                                            } else {
                                                log.debug("应该是一个关系表：" + dao.getEntityClass());
                                                // 查找到目标类型的外键属性
                                                entityAlias.put(propertyPath + "." + pk2Name, currPersistentProperty);
                                            }

                                            log.debug("添加别名：" + propertyPath + " = " + propertyPath + " : " + alias);
                                            criteria.createAlias(currPersistentProperty, alias, CriteriaSpecification.LEFT_JOIN);

                                            if (fk != null) {
                                                log.debug("添加关联条件：" + alias + "." + fk + " = " + pkAlias + "." + pkName);
                                                criteria.add(Restrictions.eq(alias + "." + fk, pkAlias + "." + pkName));
                                            }

                                            if (validExpressions != null) {
                                                criteria.add(Restrictions.sqlRestriction(validExpressions));
                                            }

                                            aliasMap.put(alias, relationObjClass);
                                            entityAlias.put(propertyPath, alias);
                                        }
                                    }
                                }
                                if (alias != null) {
                                    pkAlias = alias;
                                    alias = null;
                                }
                            }
                        }
                    }
                }
            } else {
                if (i != names.length - 1) {
                    // 中间级，非实体,不应该哦， Ingeger，Sting，不可能
                    log.debug("关联对象不是是实体");
                    throw new Exception("中间级对象，非实体对象！！！");
                }
            }

            if (alias != null) {
                pkAlias = alias;
                alias = null;
            }

            if (valueClasses != null) {
                valueClasses.add(fkEntityClass);
            }

            // 非最后一轮，变量迭代
            if (i < names.length - 1) {
                pkEntity = fkEntity;
                pkEntityClass = fkEntityClass;
                fkEntity = null;
                fkEntityClass = null;
            }
        }

        persistentPropertyValue = fkEntity;

        // 如果中途没有使用替代属性
        if (!entityAlias.containsKey(aliasName + "." + propertyName)) {
            entityAlias.put(aliasName + "." + propertyName, pkAlias + "." + currPropertyName);
        }

        return persistentPropertyValue;
    }

    /**
     * 按实体名检索dao
     *
     * @param entityName
     * @return
     */
    private HibernateEntityDao<?, Serializable> getDao(String entityName) {
        HibernateEntityDao<?, Serializable> dao = null;
        for (Entry<Class<?>, HibernateEntityDao<?, Serializable>> daoEntry : daoMap.entrySet()) {
            if (daoEntry.getKey().getSimpleName().equalsIgnoreCase(entityName)) {
                dao = daoEntry.getValue();
                break;
            }
        }
        return dao;
    }

    private String getNewAlias(String currPropertyName, Map<String, Class<?>> aliasMap) {
        String newAlias = currPropertyName;

        int i = 0;
        while (aliasMap.containsKey(newAlias)) {
            newAlias = currPropertyName + "_" + (++i);
        }

        return newAlias;
    }

    private Criteria addPropertyCriteria(Criteria criteria, String propertyName, Object value) {
        if (criteria == null)
            criteria = createCriteria();
        if (value == null) {
            criteria.add(Restrictions.isNull(propertyName));
        } else {
            criteria.add(Restrictions.eq(propertyName, value));
        }
        return criteria;
    }

    private Criteria addFirstAndMaxResults(Criteria criteria, long... firstAndMaxResults) {
        if (criteria == null)
            criteria = createCriteria();

        if (firstAndMaxResults.length > 0) {
            criteria.setFirstResult((int) firstAndMaxResults[0]);
            if (firstAndMaxResults.length > 1) {
                criteria.setMaxResults((int) firstAndMaxResults[1]);
            }
        }
        return criteria;
    }

    public Criteria addOrder(Criteria criteria, String orderBy) {
        if (criteria == null)
            criteria = createCriteria();
        if (orderBy != null) {
            String[] orderFields = orderBy.split(",");
            for (String orderField : orderFields) {
                String field = null;
                boolean isAsc = true;
                String[] orderString = orderField.split(" ");
                if (orderString.length > 0) {
                    field = orderString[0];
                }
                if (orderString.length > 1 && "DESC".equalsIgnoreCase(orderString[1])) {
                    isAsc = false;
                }
                if (field != null && field.length() > 0) {
                    if (isAsc) {
                        criteria.addOrder(Order.asc(field));
                    } else {
                        criteria.addOrder(Order.desc(field));
                    }
                }
            }
        }
        return criteria;
    }

    /**
     * 去除hql的select 子句，未考虑union的情况,用于pagedQuery.
     *
     * @param hql 查询
     */
    private static String removeSelect(String hql) {
        StringUtils.isNotEmpty(hql);
        int beginPos = hql.toLowerCase().indexOf("from");
        Assert.isTrue(beginPos != -1, " hql : " + hql + " must has a keyword 'from'");
        return hql.substring(beginPos);
    }

    /**
     * 去除hql的orderby 子句，用于pagedQuery.
     *
     * @param hql 查询
     */
    private static String removeOrders(String hql) {
        StringUtils.isNotEmpty(hql);
        Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(hql);
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(sb, "");
        }
        m.appendTail(sb);
        return sb.toString();
    }

    public void setFlushModeCOMMIT() {
        getCurrentSession().setFlushMode(FlushMode.COMMIT);
    }

    /**
     * 获得投影查询结果
     *
     * @param criteria 查询条件
     * @return 结果
     */
    public List<?> findProjections(Criteria criteria) {
        return criteria.list();
    }

    /**
     * 0.0 Description: 根据属性名获得对应字段名
     * <p>
     * CreateTime: 2010-6-7
     *
     * @param propertyName 属性名
     * @return 结果
     */
    public String getColumnName(String propertyName) {
        String colName = null;

        List<String> resultList = new ArrayList<>();
        SessionFactory factory = getHibernateTemplate().getSessionFactory();
        AbstractEntityPersister classMetadata = (SingleTableEntityPersister) factory.getClassMetadata(entityClass);
        boolean isCollection = classMetadata.getClassMetadata().getPropertyType(propertyName).isCollectionType();
        if (!isCollection) {
            for (String columnName : classMetadata.getPropertyColumnNames(propertyName)) {
                resultList.add(columnName);
            }
        }
        if (resultList != null && resultList.size() > 0) {
            return resultList.get(0);
        }
        return colName;
    }

    /**
     * @param obj          属性所在对象
     * @param PropertyName 属性变量名称
     * @return 返回属性变量名称为PropertyName的属性值
     */

    public Object getPropertyValue(Object obj, String PropertyName) {

        ClassMetadata classMetadata = getHibernateTemplate().getSessionFactory().getClassMetadata(obj.getClass());

        return classMetadata.getPropertyValue(obj, PropertyName);

    }

    /**
     * 取得对象的主键值,辅助函数.
     */
    @Override
    public PK getPK(T entity) {
        Optional.ofNullable(entity);
        Optional.ofNullable(entityClass);
        PK pk = null;
        try {
            pk = (PK) PropertyUtils.getProperty(entity, getPKName());
        } catch (Exception e) {
            pk = null;
        }

        return pk;
    }

    /**
     * 取得对象的主键名,辅助函数.
     */
    @Override
    public String getPKName() {
        return getPkNameByEntityClass(entityClass);
    }

    /**
     * 取得指定实体类的主键属性名,辅助函数.
     *
     * @return
     */
    @Override
    public String getPkNameByEntityClass(Class<?> entityClass) {
        StandardServiceRegistry standardServiceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
        Metadata metadata = new MetadataSources(standardServiceRegistry).getMetadataBuilder().build();
        PersistentClass persistentClass = metadata.getEntityBinding(entityClass.getName());
        KeyValue keyValue = persistentClass.getIdentifier();
        org.hibernate.mapping.Property property = persistentClass.getDeclaredIdentifierProperty();
        // 获取实体类的主键属性路径
        return property.getName();
    }

    /**
     * 是否是集合型外键
     *
     * @param clazz
     * @param propertyName
     * @return
     */
    public boolean isForeignKey(Class<?> clazz, String propertyName) {
        boolean result = false;

        Optional.ofNullable(clazz);
        ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
        if (meta != null) {
            org.hibernate.type.Type type = meta.getPropertyType(propertyName);
            result = type != null && type.isCollectionType();
        }

        return result;
    }

    public void flush() {
        getHibernateTemplate().flush();
    }

    public void clear() {
        getHibernateTemplate().clear();
    }

    @Override
    public long getCount(Page<T> page) {
        long count = 0;
        T example = page.getFindByExample();
        String orderBy = page.getOrderFields();
        String propertyList = (String) page.getCondition().get(PROPERTY_LIST);

        Criteria criteria = this.createCriteria();

        if (example != null) {
            this.addExampleCriteria(criteria, example, null, propertyList);
        }
        this.addOrder(criteria, orderBy);
        count = getCount(criteria);

        return count;
    }

    @Override
    public long getCountByProperty(String propertyName, Object value, String orderBy) {
        long count = 0;

        Criteria criteria = this.createCriteria();

        this.addPropertyCriteria(criteria, propertyName, value);
        this.addOrder(criteria, orderBy);
        count = getCount(criteria);

        return count;
    }

    @Override
    public void merge(T entity) {
        getHibernateTemplate().merge(entity);
    }

    @Override
    public List<T> findBy(Criteria criteria) {
        List<T> list = (List<T>) criteria.list();
        return list;
    }

    @Override
    public javax.persistence.Query createQuery(String hql, Object... values) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 执行无返回值的存储过程
     *
     * @param procName sql语句
     * @param values   值
     * @throws SQLException
     */
    @Override
    public void callProc(String procName, Object... values) throws SQLException {
        Session session = getHibernateTemplate().getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        Connection connection = session.disconnect();// 待纠正
        CallableStatement proc = connection.prepareCall(procName);
        for (int i = 0; i < values.length; i++) {
            if (values[i] instanceof Integer) {
                proc.setInt(i + 1, (Integer) values[i]);
            } else if (values[i] instanceof Long) {
                proc.setLong(i + 1, (Long) values[i]);
            } else if (values[i] instanceof String) {
                proc.setString(i + 1, (String) values[i]);
            } else if (values[i] instanceof Boolean) {
                proc.setBoolean(i + 1, (Boolean) values[i]);
            } else {

            }
        }
        proc.executeUpdate();
        tx.commit();
        proc.close();
        connection.close();
        session.close();

    }

    /**
     * 检查该类型是否为可持久化类
     *
     * @param clazz
     * @return
     */
    @Override
    public boolean isEntity(Class<?> clazz) {
        boolean isEntity = false;
        if (clazz != null) {
            ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
            if (meta != null) {
                isEntity = true;
            }
        }

        return isEntity;
    }

    /**
     * 判断指定属性是否是持久化属性
     *
     * @param propertyName
     * @return
     */
    @Override
    public boolean isPersistentProperty(String propertyName) {
        return isPersistentProperty(entityClass, propertyName);
    }

    /**
     * 判断指定属性是否是持久化属性(包括主键)
     *
     * @param propertyName
     * @return
     */
    @Override
    public <E> boolean isPersistentProperty(Class<E> clazz, String propertyName) {
        boolean result = false;
        ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
        if (meta != null) {
            if (meta.getIdentifierPropertyName().equals(propertyName)) {
                result = true;
            } else {
                String[] properties = meta.getPropertyNames();
                if (properties != null) {
                    for (String prop : properties) {
                        if (prop.equals(propertyName)) {
                            result = true;
                            break;
                        }
                    }
                }
            }
        }

        return result;
    }

    /**
     * 根据实体类型及其主键，获取其持久化对象
     */
    @Override
    public Object getByClass(Object value) {
        Object entity = null;

        ClassMetadata meta = getSessionFactory().getClassMetadata(value.getClass());
        if (meta != null) {
            String idName = meta.getIdentifierPropertyName();
            Serializable id;
            try {
                id = (Serializable) PropertyUtils.getProperty(value, idName);
            } catch (Exception e) {
                id = null;
            }
            if (id != null) {
                entity = getHibernateTemplate().get(value.getClass(), id);
            }
        }
        return entity;
    }

    @Override
    public List<Map<String, Object>> getEntityNameList() {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

        Map<?, ?> map = getSessionFactory().getAllClassMetadata();
        for (Object metaKey : map.keySet()) {
            ClassMetadata meta = (ClassMetadata) map.get(metaKey);
            if (meta != null) {
                Map<String, Object> item = new HashMap<String, Object>();
                item.put("id", meta.getEntityName());
                item.put("name", meta.getEntityName());
                list.add(item);
            }
        }
        ;
        return list;
    }

    @Override
    public long getCount(String condition) {
        String hql = "select count(*) from " + entityClass.getSimpleName() + " as " + aliasName + " where " + condition;
        List<Long> result = (List<Long>) getHibernateTemplate().find(hql);

        return result.get(0);
    }

    /**
     * 获取外键引用对象列表
     *
     * @param objectClass
     * @param aliasNames  别名列表，逗号分隔
     * @param entityPo    实体类
     * @return 外键引用对象列表
     * @throws Exception 可能的异常
     */
    public Map<String, List<?>> getRefListMap(Class<?> objectClass, String aliasNames, Object entityPo) throws Exception {
        List<Map<String, Object>> classList = getEntityNameList();
        Class<?> pkClass;
        Object pkValue;
        try {
            pkClass = BeanUtilsExt.getPropertyType(objectClass, getPkNameByEntityClass(objectClass));
            String pkName = getPkNameByEntityClass(objectClass);
            pkValue = BeanUtilsExt.getPropertyValue(entityPo, pkName);
        } catch (Exception e1) {
            pkClass = null;
            pkValue = null;
        }

        // 构建主键对象别名列表，以便以此为参照在启动表中查找相关的外键关系
        List<String> entityNames = new ArrayList<String>();
        entityNames.add(objectClass.getSimpleName());
        for (String aliasName : aliasNames.split(",")) {
            log.debug("aliasName.length()=" + aliasName.length());
            if (aliasName != null && aliasName.length() > 1) {
                if (!aliasName.equalsIgnoreCase(objectClass.getSimpleName()))
                    entityNames.add(aliasName);
            }
        }

        Map<String, List<? extends Object>> refObjectMap = new HashMap<String, List<? extends Object>>();
        // 遍历所有的实体类
        for (Map<String, Object> item : classList) {
            String className = (String) item.get("id");
            log.debug("检查类 id=" + item.get("id") + " name=" + className);
            Class<? extends Object> clazz = (Class<?>) Class.forName(className);
            // 排除目标类，好像不应该排除哦？？
            if (clazz != objectClass) {
                String[] propertyStrings = getProperties((Class<Object>) clazz);
                // 遍历要检查的的实体类的所有持久化属性
                for (String property : propertyStrings) {
                    try {
                        Class<?> propertyClass = BeanUtilsExt.getPropertyType(clazz, property);
                        if (propertyClass != null) {
                            List<Object> refObjectList = null;
                            if (isEntity(propertyClass)) {
                                // 是外键实体类
                                if (propertyClass.equals(objectClass)) {
                                    // 是要找的目标
                                    if (isPersistentProperty(propertyClass, property)) {
                                        // 是一个持久化属性
                                        log.debug("外键属性：" + property);
                                        refObjectList = (List<Object>) findByProperty(propertyClass, property, entityPo, "");
                                    } else {
                                        // 不是持久化属性，得查一下
                                    }
                                }
                            } else {
                                // 不是外键实体类，那么是否匹配外键主键类呢
                                if (propertyClass.equals(pkClass)) {
                                    for (String entityName : entityNames) {
                                        String property1 = entityName.substring(0, 1).toLowerCase() + entityName.substring(1) + "Id";
                                        String priperty2 = entityName.substring(0, 1).toUpperCase() + entityName.substring(1) + "Id";
                                        if (property.equals(property1) || property.endsWith(priperty2)) {
                                            log.debug("实体类：" + clazz.getSimpleName() + "外键属性：" + property);
                                            refObjectList = (List<Object>) findByProperty(clazz, property, pkValue, "");
                                        }
                                    }
                                }
                            }
                            if (refObjectList != null && refObjectList.size() > 0) {
                                refObjectMap.put(clazz.getSimpleName() + "." + property, refObjectList);
                            }
                        }
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return refObjectMap;
    }

    /**
     * 替换外键引用，即更换外键对象引用方
     *
     * @param objectClass
     * @param aliasNames
     * @param srcId
     * @param tarId
     * @return 成功替换外键类型数
     * @throws Exception
     */
    @Override
    public int replaceRef(Class<?> objectClass, String aliasNames, Serializable srcId, Serializable tarId) throws Exception {
        int count = 0;

        Object srcEntityPo = (T) this.getHibernateTemplate().get(objectClass, srcId);
        Object tarEntityPo = (T) this.getHibernateTemplate().get(objectClass, tarId);

        List<Map<String, Object>> classList = getEntityNameList();
        Class<?> pkClass;
        Object pkValue;
        try {
            pkClass = BeanUtilsExt.getPropertyType(objectClass, getPkNameByEntityClass(objectClass));
            String pkName = getPkNameByEntityClass(objectClass);
            pkValue = BeanUtilsExt.getPropertyValue(srcEntityPo, pkName);
        } catch (Exception e1) {
            pkClass = null;
            pkValue = null;
        }

        // 构建主键对象别名列表，以便以此为参照在启动表中查找相关的外键关系
        List<String> entityNames = new ArrayList<String>();
        entityNames.add(objectClass.getSimpleName());
        for (String aliasName : aliasNames.split(",")) {
            log.debug("aliasName.length()=" + aliasName.length());
            if (aliasName != null && aliasName.length() > 1) {
                if (!aliasName.equalsIgnoreCase(objectClass.getSimpleName()))
                    entityNames.add(aliasName);
            }
        }
        // 遍历所有的实体类
        for (Map<String, Object> item : classList) {
            String className = (String) item.get("id");
            log.debug("检查类 id=" + item.get("id") + " name=" + className);
            Class<? extends Object> clazz = (Class<?>) Class.forName(className);
            // 排除目标类，好像不应该排除哦？？
            if (clazz != objectClass) {
                String[] propertyStrings = getProperties((Class<Object>) clazz);
                // 遍历要检查的的实体类的所有持久化属性
                for (String property : propertyStrings) {
                    try {
                        Class<?> propertyClass = BeanUtilsExt.getPropertyType(clazz, property);
                        if (propertyClass != null) {
                            List<Object> refObjectList = null;
                            if (isEntity(propertyClass)) {
                                // 是外键实体类
                                if (propertyClass.equals(objectClass)) {
                                    // 是要找的目标
                                    if (isPersistentProperty(propertyClass, property)) {
                                        // 是一个持久化属性
                                        log.debug("外键属性：" + property);
                                        refObjectList = (List<Object>) findByProperty(propertyClass, property, srcEntityPo, "");
                                        for (Object refObj : refObjectList) {
                                            BeanUtilsExt.setPropertyValue(refObj, property, tarEntityPo);
                                            getHibernateTemplate().update(refObj);
                                        }
                                    } else {
                                        // 不是持久化属性，得查一下
                                    }
                                }
                            } else {
                                // 不是外键实体类，那么是否匹配外键主键类呢
                                if (propertyClass.equals(pkClass)) {
                                    for (String entityName : entityNames) {
                                        String property1 = entityName.substring(0, 1).toLowerCase() + entityName.substring(1) + "Id";
                                        String priperty2 = entityName.substring(0, 1).toUpperCase() + entityName.substring(1) + "Id";
                                        if (property.equals(property1) || property.endsWith(priperty2)) {
                                            log.debug("实体类：" + clazz.getSimpleName() + "外键属性：" + property);
                                            refObjectList = (List<Object>) findByProperty(clazz, property, pkValue, "");
                                            for (Object refObj : refObjectList) {
                                                BeanUtilsExt.setPropertyValue(refObj, property, tarId);
                                                getHibernateTemplate().update(refObj);
                                            }
                                        }
                                    }
                                }
                            }
                            if (refObjectList != null && refObjectList.size() > 0) {
                                count++;
                            }
                        }
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return count;
    }

    @Override
    public <T1, PK1 extends Serializable> HibernateEntityDao<T1, PK1> getBaseDao(Class<T1> clazz1) {
        HibernateEntityDao<T1, PK1> dao = null;

        if (daoMap.containsKey(clazz1)) {
            dao = (HibernateEntityDao<T1, PK1>) daoMap.get(clazz1);
        } else {
            dao = new HibernateEntityDao<T1, PK1>(clazz1);
            dao.setSessionFactory(getSessionFactory());
            daoMap.put(clazz1, (HibernateEntityDao<?, Serializable>) dao);
        }

        return dao;
    }

    /**
     * 指定的实体属性是否非空
     *
     * @param entityClass  实体类
     * @param propertyName 属性名
     * @return 结果
     */
    @Override
    public boolean isPropertyNonNull(Class<?> entityClass, String propertyName) {
        boolean result = false;

        ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);
        if (meta != null) {
            String[] properties = meta.getPropertyNames();
            if (properties != null) {
                int index = -1;
                for (int i = 0; i < properties.length; i++) {
                    String prop = properties[i];
                    if (prop.equals(propertyName)) {
                        index = i;
                        break;
                    }
                }
                if (index != -1) {
                    result = meta.getPropertyNullability()[index];
                }
            }
        }

        return result;
    }

}
